﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using DSFramework;

using HtmlAgilityPack;

using System.Text.RegularExpressions;
using static System.Net.WebRequestMethods;
using System.Security.Policy;
using System.IO;
using System.Net;
using static System.Net.Mime.MediaTypeNames;

namespace GetWebsite
{
    /// <summary>
    /// 博客园
    /// </summary>
    public class CnBlog
    {
        /// <summary>
        /// 保存当前从网页抓取的内容
        /// </summary>
        public static List<CnBlogInfo> blogInfos { get; set; } = new List<CnBlogInfo>();
        /// <summary>
        /// 保存已经存在的内容 方便后续判断
        /// </summary>
        public static List<CnBlogInfo> caches { get; set; } = new List<CnBlogInfo>();

        private static StringBuilder sbBlog = new StringBuilder();

        public CnBlog()
        {
            Console.WriteLine("CnBlog实例化了 ");
            foreach (var item in CnBlog.caches)
            {
                if (item.IsDLImage == 0)
                {
                    string rndId = Guid.NewGuid().ToString("N");
                    item.Id = rndId;
                    item.IsDLImage = 1;
                    //GetImages(item);
                    SQL.DB.Updateable(item).ExecuteCommand();
                }
            }
        }

        /// <summary>
        /// 获取并推送博客
        /// </summary>
        /// <param name="mailConfig"></param>
        /// <param name="url"></param>
        /// <param name="param"></param>
        public void GetAndSendBlogs(MailConfig mailConfig, string url = "https://www.cnblogs.com/", string param = "")
        {
            if (mailConfig == null) return;

            GetHomeBlog(url, param);


            foreach (var item in blogInfos)
            {
                Console.WriteLine($"Url:{item.Url}");
                //更新数据库
                UpdateBlogInfo(item, 0, false);
            }

            //获取缓存中还未发送的文章
            if (caches.Count >= 5)
            {
                for (int i = 0; i < caches.Count; i++)
                {
                    //更新数据库
                    UpdateBlogInfo(caches[i], 1, true);
                }

                MailHelper.SendMail(mailConfig, mailConfig.ReceiveList, mailConfig.Name, $"UnitySir->博客园[首页]文章定时推送={DateTime.Now:yyyy-MM-dd HH:mm}=", sbBlog.ToString());
                Console.WriteLine($"发送邮件：{DateTime.Now:yyyy-MM-dd HH:mm:ss}");
                CnBlog.caches.Clear();
            }

            sbBlog.Clear();
            CnBlog.blogInfos.Clear();
        }


        /// <summary>
        /// 获取单个网页的内容
        /// </summary>
        /// <param name="url"></param>
        /// <param name="param"></param>
        public (bool isTrue, string msg) GetSingleContent(string url, string param = "")
        {
            if (SQL.DB.Queryable<CnBlogInfo>().Any(it => it.Url.Equals(url)))
            {
                return (false, "文章已在数据库!");//如果保存有相同的文章则直接返回
            }

            try
            {
                string html = HttpHelper.HttpGet(url, param);
                HtmlDocument doc = new HtmlDocument();
                doc.LoadHtml(html);

                //获取主要内容
                var mainContent = doc.DocumentNode.SelectSingleNode("//div[@class='post']") ?? default;

                //标题元素
                var titleElem = mainContent?.SelectSingleNode("h1");
                if (titleElem == null)
                {
                    titleElem = mainContent?.SelectSingleNode("h2"); ;
                }
                if (titleElem == null)
                {
                    titleElem = mainContent?.SelectSingleNode("div[@class='postTitle']/a"); ;
                }
                //获取标题
                var _title = titleElem?.InnerText.Replace("\r\n", "").Trim().Replace("&lt;", "<").Replace("&gt;", ">") ?? string.Empty;
                //获取url
                var _url = url;
                //摘要元素
                var summaryElem = doc.DocumentNode.SelectSingleNode("//meta[@name='description']") ?? default;
                //获取摘要
                var _summary = summaryElem?.Attributes["content"].Value.Replace("\r\n", "").Trim() ?? string.Empty;
                //数据项底部元素
                var footElem = doc.DocumentNode.SelectSingleNode("//div[@class='postDesc']") ?? default;
                if (footElem == null)
                {
                    footElem = doc.DocumentNode.SelectSingleNode("//p[@class='postfoot']") ?? default;
                }
                if (footElem == null)
                {
                    footElem = doc.DocumentNode.SelectSingleNode("//div[@class='postfoot']") ?? default;
                }
                //获取作者
                var _author = footElem?.SelectSingleNode("a")?.InnerText.Replace("\r\n", "").Trim() ?? string.Empty;
                //获取文章发布时间
                var _publishTime = Regex.Match(footElem?.InnerText.Replace("\r\n", "").Trim(), "\\d+-\\d+-\\d+ \\d+:\\d+").Value ?? string.Empty;

                //获取网页内容
                var htmlMainContent = doc.DocumentNode.SelectSingleNode("//div[@id='cnblogs_post_body']");
                string content = MailTemplete.CompleteContentTemplete.Replace("#hh", "</br>").Replace("#content", htmlMainContent.InnerHtml);

                CnBlogInfo blogInfo = new CnBlogInfo { Author = _author, Title = _title, Url = _url, Summary = _summary, PublishTime = _publishTime, WebsiteName = "CN", AllContent = content };

                UpdateBlogInfo(blogInfo, 0, false);

                return (false, "文章已保存!");
            }
            catch (Exception e)
            {
                UtilitieTools.Log($"获取文章失败:{e}", "GetSingleContent");
                return (false, "文章保存失败!请查看异常日志!"); ;
            }
        }

        /// <summary>
        /// 获取博客内容
        /// </summary>
        /// <param name="mailConfig"></param>
        /// <param name="url">博客地址</param>
        /// <param name="param"></param>
        private string GetContent(CnBlogInfo item, string param = "")
        {
            var htmlMainContent = GetHTMLBody(item.Url, param);
            if (htmlMainContent == null) return string.Empty;
            string content = MailTemplete.CompleteContentTemplete.Replace("#hh", "</br>").Replace("#content", htmlMainContent.InnerHtml);
            return content;
        }

        /// <summary>
        /// 获取 网页所有图片
        /// </summary>
        /// <param name="url"></param>
        private void GetImages(CnBlogInfo cnBlogInfo, string param = "")
        {
            List<string> imgUrls = new List<string>();
            var htmlMainContent = GetHTMLBody(cnBlogInfo.Url, param);
            if (htmlMainContent == null) return;
            var imgs = htmlMainContent.SelectNodes("//img");
            foreach (var img in imgs)
            {
                if (img.Attributes.Contains("src"))
                    imgUrls.Add(img.Attributes["src"].Value);
            }
            imgUrls.RemoveAt(imgUrls.Count - 1);//移除最后一个没用的图片

            foreach (var item in imgUrls)
            {
                if (!item.Contains("http")) continue;
                DownloadUrlFile(item, $"Images/{cnBlogInfo.Id}/");
            }
        }

        /// <summary>
        /// 下载服务器文件至客户端
        /// </summary>
        /// <param name="url">被下载的文件地址，绝对路径</param>
        /// <param name="dir">另存放的目录</param>
        private void DownloadUrlFile(string url, string dir)
        {
            try
            {
                WebClient client = new WebClient();
                string fileName = Path.GetFileName(url);  //被下载的文件名
                string path = dir + fileName;   //另存为的绝对路径＋文件名

                if (!Directory.Exists(dir))
                {
                    Directory.CreateDirectory(dir);
                }
                if (!System.IO.File.Exists(path))
                {
                    client.DownloadFileAsync(new Uri(url), path);
                }
            }
            catch (Exception)
            {
                Console.WriteLine("图片下载失败");
            }

        }

        /// <summary>
        /// 获取首页文章
        /// </summary>
        /// <param name="url">官网地址</param>
        /// <param name="param">需要的参数</param>
        private void GetHomeBlog(string url, string param)
        {
            string html = HttpHelper.HttpGet(url, param);

            HtmlDocument doc = new HtmlDocument();
            doc.LoadHtml(html);

            //获取所有文章数据项
            var itemBodys = doc.DocumentNode.SelectNodes("//section[@class='post-item-body']");

            foreach (var itemBody in itemBodys)
            {
                //标题元素
                var titleElem = itemBody.SelectSingleNode("div[@class='post-item-text']/a") ?? default;
                //获取标题
                var _title = titleElem?.InnerText.Replace("\r\n", "").Trim() ?? default;
                //获取url
                var _url = titleElem?.Attributes["href"]?.Value.Replace("\r\n", "").Trim() ?? default;
                //摘要元素
                var summaryElem = itemBody.SelectSingleNode("div[@class='post-item-text']/p") ?? default;
                //获取摘要
                var _summary = summaryElem?.InnerText.Replace("\r\n", "").Trim() ?? default;
                //数据项底部元素
                var footElem = itemBody.SelectSingleNode("footer[@class='post-item-foot']") ?? default;
                //获取作者
                var _author = footElem?.SelectSingleNode("a")?.InnerText.Replace("\r\n", "").Trim() ?? default;
                //获取文章发布时间
                var _publishTime = Regex.Match(footElem?.InnerText.Replace("\r\n", "").Trim(), "\\d+-\\d+-\\d+ \\d+:\\d+").Value ?? default;

                if (SQL.DB.Queryable<CnBlogInfo>().Any(it => it.Url.Equals(_url)))
                {
                    continue;
                }

                var blogInfo = new CnBlogInfo { Author = _author, Title = _title, Url = _url, Summary = _summary, PublishTime = _publishTime, WebsiteName = "CN" };
                blogInfos.Add(blogInfo);
            }

        }

        /// <summary>
        /// 更新博客信息，未发送和已发送的
        /// </summary>
        /// <param name="item"></param>
        /// <param name="isSend">是否发送</param>
        /// <param name="isUpdate">更新还是插入</param>
        private void UpdateBlogInfo(CnBlogInfo item, int isSend, bool isUpdate)
        {
            string content = GetContent(item);

            if (string.IsNullOrEmpty(content))
            {
                content = item.AllContent;
            }
            if (string.IsNullOrEmpty(content)) return;
            var curtime = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss}";
            item.IsSendToEmail = isSend;//已发送
            if (isUpdate)
            {
                sbBlog.AppendLine(MailTemplete.MainContentTemplete.Replace("#title", item.Title).Replace("#blogurl", item.Url).Replace("#summary", item.Summary).Replace("#author", item.Author).Replace("#publishtime", item.PublishTime).Replace("#hh", "<br/>"));
                sbBlog.AppendLine(content);

                item.LastUpdateTime = curtime;
                SQL.DB.Updateable(item).ExecuteCommand();
            }
            else
            {//第一次插入数据时，先初始化一些数据 

                item.AllContent = content;
                item.SavedTime = curtime;
                item.LastUpdateTime = curtime;
                string rndId = Guid.NewGuid().ToString("N");
                item.Id = rndId;
                item.IsDLImage = 1;
                //GetImages(item);
                SQL.DB.Insertable(item).ExecuteCommand();
                CnBlog.caches.Add(item);
            }
        }

        /// <summary>
        /// 获取网页内容主体
        /// </summary>
        /// <param name="url"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        private HtmlNode GetHTMLBody(string url, string param)
        {
            string html = HttpHelper.HttpGet(url, param);
            if (string.IsNullOrEmpty(html)) return null;
            HtmlDocument doc = new HtmlDocument();
            doc.LoadHtml(html);

            var htmlMainContent = doc.DocumentNode.SelectSingleNode("//div[@id='cnblogs_post_body']");
            return htmlMainContent;
        }

        #region 需要登录才能使用
        /// <summary>
        /// 获取博客园IT新闻
        /// </summary>
        /// <param name="url"></param>
        /// <param name="param"></param>
        private void GetNews(string url = "https://www.cnblogs.com/news/", string param = "")
        {
            string html = HttpHelper.HttpGet(url, param);

            HtmlDocument doc = new HtmlDocument();
            doc.LoadHtml(html);

            //获取所有文章数据项
            var itemBodys = doc.DocumentNode.SelectNodes("//div[@class='news_block']");

            foreach (var itemBody in itemBodys)
            {
                //标题元素
                var titleElem = itemBody.SelectSingleNode("div[@class='content']/h2/a") ?? default;
                //获取标题
                var _title = titleElem?.InnerText ?? default;
                //获取url
                var _url = url + titleElem?.Attributes["href"]?.Value ?? default;
                //摘要元素
                var summaryElem = itemBody.SelectSingleNode("div[@class='content']/div[@class='entry_summary']") ?? default;
                //获取摘要
                var _summary = summaryElem?.InnerText.Replace("\r\n", "").Trim() ?? default;
                //数据项底部元素
                var footElem = itemBody.SelectSingleNode("div[@class='content']/div[@class='entry_footer']") ?? default;
                //获取作者
                var _author = footElem?.SelectSingleNode("a")?.InnerText.Replace("\r\n", "").Trim() ?? default;
                //获取文章发布时间
                var _publishTime = Regex.Match(footElem?.InnerText, "\\d+-\\d+-\\d+ \\d+:\\d+").Value ?? default;

                CnBlogInfo blogInfo = new CnBlogInfo { Author = _author, Title = _title, Url = _url, Summary = _summary, PublishTime = _publishTime, WebsiteName = "CN" };
                //blogNewsInfos.Add(blogInfo);
            }
        }
        #endregion

    }
}
